
#include "GraphicsWindowStatics.h"


GraphicsWindowPrimer* gwp;



GraphicsWindowStatics::GraphicsWindowStatics()
{
#if defined(WIN_WIN)
	HGLRC		hRC = NULL;		//rendering context
	HDC			hDC = NULL;		//device context
	HWND		hWnd = NULL;	//window handle
	//ZK commented out
	//HINSTANCE	hInstance;		//instance of app

	active = true;
	mouseDown = false;
	done = false;
#endif
}

/*----------------------------------------------------------------------------*/
GraphicsWindowStatics::~GraphicsWindowStatics()
{
#if defined(WIN_WIN)
	
#endif
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::initWindow(GraphicsWindowPrimer* pgwp)
{	
	gwp = pgwp;
	initFuncs();
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::initFuncs()
{

#if defined(GLUT_WIN)
	//set glut functions
	glutDisplayFunc(GraphicsWindowStatics::CallBackDisplayFunc);
	glutReshapeFunc(GraphicsWindowStatics::CallBackReshapeFunc);
	glutKeyboardFunc(GraphicsWindowStatics::CallBackKeyboardFunc);
	glutIdleFunc(GraphicsWindowStatics::CallBackIdleFunc);
	glutMotionFunc(GraphicsWindowStatics::CallBackMotionFunc);
	glutMouseFunc(GraphicsWindowStatics::CallBackMouseFunc);
	glutPassiveMotionFunc(GraphicsWindowStatics::CallBackPassiveMotionFunc); 
	glutSpecialFunc(GraphicsWindowStatics::CallBackSpecialFunc);
#endif

}

#if defined(WIN_WIN)
/*----------------------------------------------------------------------------*/
bool GraphicsWindowStatics::winCreateWindow(string winName, int w, int h, int x, int y, bool pfullscreen)
{
	fullscreen = pfullscreen;

	int	PixelFormat;	//stores pixel format mode

	WNDCLASS wc;	//window class struct

	DWORD	dwExStyle;	//window extended style
	DWORD	dwStyle;	//window style

	RECT WindowRect;	//grabs upper left/ lower right
	WindowRect.left=(long)0;
	WindowRect.right=(long)w;
	WindowRect.top=(long)0;
	WindowRect.bottom=(long)h;


	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Move, And Own DC For Window
	wc.lpfnWndProc		= (WNDPROC) stWndProc;					// WndProc Handles Messages
	wc.cbClsExtra		= 0;									// No Extra Window Data
	wc.cbWndExtra		= 0;									// No Extra Window Data
	wc.hInstance		= hInstance;							// Set The Instance
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
	wc.hbrBackground	= NULL;									// No Background Required For GL
	wc.lpszMenuName		= NULL;									// We Don't Want A Menu
	wc.lpszClassName	= "GraphicsWindowStatics";	

	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, "failed to register window class", "Error", MB_OK);
		return  false;
	}

	if (fullscreen)
	{
		DEVMODE dmScreenSettings;									//device mode
		memset (&dmScreenSettings, 0, sizeof (dmScreenSettings));	//mkae sure memory is cleared
		dmScreenSettings.dmSize=sizeof (dmScreenSettings);			//size of devmode struct
		dmScreenSettings.dmPelsHeight = h;							//selected scren height
		dmScreenSettings.dmPelsWidth = w;							//selected screen width
		dmScreenSettings.dmBitsPerPel = 32;							//selected bits per pixel
		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		if (ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
		{

			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "GraphicsWindowStatics",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
				fullscreen = false;
			else
				return false;
		}

	}

	if(fullscreen)
	{
		dwExStyle=WS_EX_APPWINDOW;
		dwStyle=WS_POPUP;
		ShowCursor(true);
	}
	else
	{
		dwExStyle= WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
		dwStyle = WS_OVERLAPPEDWINDOW;
	}

	AdjustWindowRectEx (&WindowRect, dwStyle, false, dwExStyle);

		
	if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window
								"GraphicsWindowStatics",						// Class Name
								winName.c_str(),					// Window Title
								WS_CLIPSIBLINGS |					// Required Window Style
								WS_CLIPCHILDREN |					// Required Window Style
								dwStyle,							// Selected Window Style
									x, y,							// Window Position
								WindowRect.right-WindowRect.left,	// Calculate Adjusted Window Width
								WindowRect.bottom-WindowRect.top,	// Calculate Adjusted Window Height
								NULL,								// No Parent Window
								NULL,								// No Menu
								hInstance,							// Instance
								(void *)this)))						// Don't Pass Anything To WM_CREATE
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to create window", "error", MB_OK);
		return false;
	}

	static	PIXELFORMATDESCRIPTOR pfd=	// pfd Tells Windows How We Want Things To Be
	{
		sizeof(PIXELFORMATDESCRIPTOR),	// Size Of This Pixel Format Descriptor
		1,								// Version Number
		PFD_DRAW_TO_WINDOW |			// Format Must Support Window
		PFD_SUPPORT_OPENGL |			// Format Must Support OpenGL
		PFD_DOUBLEBUFFER,				// Must Support Double Buffering
		PFD_TYPE_RGBA,					// Request An RGBA Format
		32,								// Select Our Color Depth
		0, 0, 0, 0, 0, 0,				// Color Bits Ignored
		1,								// Use Alpha Buffer
		0,								// Shift Bit Ignored
		0,								// No Accumulation Buffer
		0, 0, 0, 0,						// Accumulation Bits Ignored
		16,								// 16Bit Z-Buffer (Depth Buffer)
		1,								// Use Stencil Buffer
		0,								// No Auxiliary Buffer
		PFD_MAIN_PLANE,					// Main Drawing Layer
		0,								// Reserved
		0, 0, 0							// Layer Masks Ignored
	};
	
	if (!(hDC=GetDC(hWnd)))
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to create a device context", "Error", MB_OK);
		return false;
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC, &pfd)))
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to find a pixel format", "Error", MB_OK);
		return false;
	}

	if (!(SetPixelFormat(hDC, PixelFormat, &pfd)))
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to set the pixel format", "Error", MB_OK);
		return false;
	}

	if (!(hRC = wglCreateContext(hDC)))
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to create the rendering context", "Error", MB_OK);
		return false;
	}

	//activate the rendering context
	if (!wglMakeCurrent(hDC, hRC))
	{
		winExitMainLoop();
		MessageBox(NULL, "failed to activate the redering context", "Error", MB_OK);
		return false;
	}

	ShowWindow(hWnd, SW_SHOW);		//show our window
	SetForegroundWindow(hWnd);		//give it a higher priority
	SetFocus(hWnd);
	CallBackReshapeFunc(w, h);

	return true;
}

/*----------------------------------------------------------------------------*/
LRESULT CALLBACK GraphicsWindowStatics::stWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	GraphicsWindowStatics* pWnd;

    if (uMsg == WM_NCCREATE)
    {
        // get the pointer to the window from
        // lpCreateParams which was set in CreateWindow
        SetWindowLong(hWnd, GWL_USERDATA, 
           (long)((LPCREATESTRUCT(lParam))->lpCreateParams));
    }

    // get the pointer to the window
    pWnd = GetObjectFromWindow(hWnd);

    // if we have the pointer, go to the message handler of the window
    // else, use DefWindowProc
    if (pWnd)
        return pWnd->WndProc(hWnd, uMsg, wParam, lParam);
    else
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

/*----------------------------------------------------------------------------*/
LRESULT CALLBACK GraphicsWindowStatics::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_ACTIVATE:
			{
				if (!HIWORD(wParam))
					active = true;
				else
					active = false;

				return 0;
			}

		case WM_SYSCOMMAND:
			{
				switch (wParam)
				{
					case SC_SCREENSAVE:
					case SC_MONITORPOWER:
						return 0;
				}
				break;
			}

		case WM_CLOSE:
			{
				PostQuitMessage(0);
				return 0;
			}

		case WM_KEYDOWN:
			{
				int pressed = getASCII(wParam);	
				if (pressed != -1)
				    CallBackKeyboardFunc(pressed, LOWORD(lParam), HIWORD(lParam));
				return 0;
			}

		case WM_KEYUP:
			{
				return 0;
			}
		
		case WM_LBUTTONDOWN:
			{
				mouseDown = true;
				CallBackMouseFunc(0, 0, LOWORD(lParam), HIWORD(lParam));
				CallBackMotionFunc(LOWORD(lParam), HIWORD(lParam));
				break;
			}

		case WM_LBUTTONUP:
			{
				mouseDown = false;
				CallBackMouseFunc(0, 1, LOWORD(lParam), HIWORD(lParam));
				break;
			}

		case WM_RBUTTONDOWN:
			{
				mouseDown = true;
				CallBackMouseFunc(2, 0, LOWORD(lParam), HIWORD(lParam));
				CallBackMotionFunc(LOWORD(lParam), HIWORD(lParam));
				break;
			}

		case WM_RBUTTONUP:
			{
				mouseDown = false;
				CallBackMouseFunc(2, 1, LOWORD(lParam), HIWORD(lParam));
				break;
			}

		case WM_MOUSEMOVE:
			{
				if (mouseDown)
				    CallBackMotionFunc(LOWORD(lParam), HIWORD(lParam));	
				else
					CallBackPassiveMotionFunc(LOWORD(lParam), HIWORD(lParam));	
				break;
			}
			
		case WM_SIZE:
			{
				CallBackReshapeFunc(LOWORD(lParam), HIWORD(lParam));
				return 0;
			}
		case WM_ERASEBKGND:								// Check To See If Windows Is Trying To Erase The Background
			return 0;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

/*----------------------------------------------------------------------------*/
char GraphicsWindowStatics::getASCII(WPARAM pkey)
{	
	int key = pkey;
	if (key >=96 && key <= 105)
	{
		key -= 48;
	    return key;
	}

	if (key >=48 && key <= 59)
		return key;

	if (key !=VK_LBUTTON || key !=VK_RBUTTON)
	{
		if (key >=65 && key <=90)
		{
			if (GetKeyState(VK_CAPITAL) || GetKeyState(VK_SHIFT))
				return key;
			else
			{
				key = key +32;
				return key;
			}
		}
	}

	
	if (key == VK_LEFT || key == VK_RIGHT || key == VK_UP || key == VK_DOWN
		|| key == VK_PRIOR || key == VK_NEXT || key == VK_BACK || key == VK_SPACE)
	{
		return key;
	}

	else if (key == 190) // period
		return 46;
	else if (key == 189) //hyphen
		return 45;
	else if (key == 191) //forward slash
		return 47;
	else if (key == 220) //back slash
		return 92;
	else if (key == 188) //comma
		return 44;
	else if (key == 219) //left bracket
		return 91;
	else if (key == 221) //right bracket
		return 93;
	else if (key == 222) //apostrophy
		return 39;
	else if (key == 186) //semi-colon
		return 59;


	return -1;
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::winClearWindow()
{
	if (fullscreen)
	{
		ChangeDisplaySettings(NULL, 0);
		ShowCursor (TRUE);
	}

	if (hRC)
	{
		if (!wglMakeCurrent(NULL, NULL))
			;

		if (!wglDeleteContext(hRC))
			;

		hRC=NULL;
	}

	if (hDC && !ReleaseDC(hWnd, hDC))
	{
		hDC=NULL;
	}


	if (hWnd && !DestroyWindow(hWnd))
	{
		hWnd = NULL;
	}

	if (!UnregisterClass("GraphicsWindowStatics", hInstance))
	{
		hInstance = NULL;
	}
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::winMainLoop()
{
	winPostRedisplay();

	while(!done)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				done = true;
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		else
		{
			CallBackIdleFunc();
		}
	}
	winClearWindow();
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::winExitMainLoop()
{
	done = true;
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::winPostRedisplay()
{
	CallBackDisplayFunc();
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::winSwapBuffers()
{
	SwapBuffers(hDC);
}

#endif

/*----------------------------------------------------------------------------*/
/********************* Static functions for callbacks *************************/

void GraphicsWindowStatics::CallBackDisplayFunc(void)
{
   gwp->displayFunc();
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackIdleFunc(void)
{
   gwp->idleFunc();
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackKeyboardFunc(unsigned char key, int x, int y)
{   
   gwp->keyboardFunc(key, x, y);
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackMotionFunc(int x, int y)
{
   gwp->motionFunc(x, y);
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackMouseFunc(int button, int state, int x, int y)
{
   gwp->mouseFunc(button, state, x, y);
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackPassiveMotionFunc(int x, int y)
{
   gwp->passiveMotionFunc(x, y);
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackReshapeFunc(int w, int h)
{
   gwp->reshapeFunc(w, h);
}

/*----------------------------------------------------------------------------*/
void GraphicsWindowStatics::CallBackSpecialFunc(int key, int x, int y)
{
   gwp->specialFunc(key, x, y);
}   

/*----------------------------------------------------------------------------*/
